package com.zc.study.xml数据传输;

import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



public class WriteReadXML{


    /**
     * @category 創建XML 並且通過 輸出流 暴露出去
     * @param topstr 根節點
     * @param values  map
     * @param out 輸出流
     * @return
     * @throws Exception
     */
    public static boolean createXML(String topstr,Map<String,String> values, OutputStream out) throws Exception {
        DocumentFactory factory = DocumentFactory.getInstance();
        Document doc = factory.createDocument();
        XMLWriter writer = null;
        if(!isEmpty(topstr) && values != null){
            Element element = doc.addElement(topstr);
            for(String o : values.keySet()){
                String key = o;
                String value = values.get(o);
                createElement(element, key, value);
            }
            OutputFormat format = OutputFormat.createPrettyPrint();
            format.setEncoding("UTF-8");
            try {
//				也可以通過文件流方式
//				FileOutputStream ou = new FileOutputStream("c:\\1215.xml");
//				XMLWriter writer1 = new XMLWriter(ou, format);
//				writer1.write(doc);
//				writer1.flush();
//				writer1.close();

                writer = new XMLWriter(out, format);
                System.out.println(doc.asXML());
                writer.write(doc);
                writer.flush();
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                throw e;
            } finally {
                try {
                    if (writer != null) {
                        writer.close();
                    }
                } catch (Exception e) {
                    // TODO: handle exception
                    return false;
                }
            }
        }
        return false;
    }

    public OutputFormat createXML(Map  map,String topstr, OutputStream out) throws Exception {
        DocumentFactory factory = DocumentFactory.getInstance();
        Document doc = factory.createDocument();
        Element element = doc.addElement(topstr);
        XMLWriter writer = null;
        if (map != null) {
            writeReturnmsg(element, map);
        }
        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        try {
            writer = new XMLWriter(out, format);
            writer.write(doc);
            writer.flush();
            return format;
        } catch (IOException e) {
            throw e;
        } finally {
            try {
                if (writer == null) {
                    writer.close();
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }
    /**
     * @category 創建XML 並通過 response  暴露出去
     * @param topstr 根節點
     * @param values
     * @return
     * @throws Exception
     */
    public void uotputXML2(String topstr,Map values, HttpServletResponse response) throws Exception {
        DocumentFactory factory = DocumentFactory.getInstance();
        Document doc = factory.createDocument();
        XMLWriter writer = null;
        Writer rewriter = null;
        Element element = doc.addElement(topstr);
        createElement(element,  values);

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        try {
            response.setCharacterEncoding("UTF-8");
            rewriter = response.getWriter();
            writer = new XMLWriter(rewriter, format);
            writer.write(doc);
            System.out.println(doc.asXML());
            writer.flush();
            rewriter.flush();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw e;
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
                if (rewriter != null) {
                    rewriter.close();
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }


    /**
     * @方法說明 自定義數組方式一一對應
     * @param topstr 根節點
     * @param str 子元素
     * @param objects 元素值
     * @param response
     * @throws Exception
     */
    public void uotputXML(String topstr, String[] str,String[] objects, HttpServletResponse response) throws Exception {
        DocumentFactory factory = DocumentFactory.getInstance();
        Document doc = factory.createDocument();
        XMLWriter writer = null;
        Writer rewriter = null;
        Element element = doc.addElement(topstr);

        for (int i = 0; i < str.length && i < objects.length; i++) {
            createElement(element, str[i], objects[i]);
        }

        OutputFormat format = OutputFormat.createPrettyPrint();
        format.setEncoding("UTF-8");
        try {
            response.setCharacterEncoding("UTF-8");
            rewriter = response.getWriter();
            writer = new XMLWriter(rewriter, format);
            writer.write(doc);
            System.out.println(doc.asXML());
            writer.flush();
            rewriter.flush();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            throw e;
        } finally {
            try {
                if (writer != null) {
                    writer.close();
                }
                if (rewriter != null) {
                    rewriter.close();
                }
            } catch (Exception e) {
                // TODO: handle exception
                e.printStackTrace();
            }
        }
    }


    /**--------------------------------------------發送xml-以及讀取xml------------------------------------------------------**/
    /** 普通方式
     * 發送xml文件；
     * @param url
     * @return
     */
    public Map send_XML(String url, Map map) {
        InputStream in = null;
        OutputStream out = null;
        try {
				/*
				 * 使用URL打开一个连接
				 */
            URLConnection uc = new URL(url).openConnection();
            HttpURLConnection con = (HttpURLConnection) uc;
				/*
				 * 设置请求方法
				 */
            con.setRequestMethod("POST");
				/*
				 * 设置发送的数据类型
				 */
            con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            con.setDoOutput(true);
				/*
				 * 本方法的调用位置非常重要，一定要在实际的连接 打开之间调用 也就是说得到输出流之间调用
				 */
            con.setDoInput(true);

				/*
				 * 打开输出流，向Servlet传递xml文件中的数据
				 */
            out = con.getOutputStream();
            createXML(map, "root",out);
            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
                System.out.println("连接失败！");
            }
				/*
				 *
				 * 打开输入流，接收servlet返回的信息，并打印
				 *
				 */
            in = con.getInputStream();
				 /*
				  * 讀取輸入流
				  */
            map = readXML(in);
        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }

        }
        return map;
    }


    /**
     * main xml远程交互
     * @category 發送XML
     * @param url
     * @param topstr
     * @param values
     * @return
     */
    public static Map Send_XML(String url,String topstr,Map values) {
        InputStream in = null;
        OutputStream out = null;
        Map map = null;
        try {
//				ssl驗證發送
//				SSLContext sc = SSLContext.getInstance("SSL");
//				sc.init(null, new TrustManager[]{new TrustAnyTrustManager()}, new java.security.SecureRandom());
//				HttpsURLConnection con = (HttpsURLConnection) uc;
//				con.setSSLSocketFactory(sc.getSocketFactory());

            URLConnection uc = new URL(url).openConnection();
            HttpURLConnection con = (HttpURLConnection) uc;
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type", "multipart/related");
            con.setDoOutput(true);
            con.setDoInput(true);
            out = con.getOutputStream();
            createXML("status", values, out);
            if (con.getResponseCode() != HttpURLConnection.HTTP_OK) {
                System.out.println("连接失败！");
            }
            in = con.getInputStream();
//				 map = ReadXML(in);
            map = newReadXML(in);
        } catch (Exception e) {
            e.printStackTrace();
            // TODO: handle exception
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                }
            }
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                }
            }

        }
        return map;
    }



    /**
     * @category URL發送字符串
     * @param httpUrl
     * @param parameter
     * @return
     */
    public static Map Send_msg(String httpUrl, Map<String,String> parameter) {
        Map value = new HashMap();
        try {
            int i = 0;
            for(String o : parameter.keySet()){
                if(!isEmpty(o) && !isEmpty(parameter.get(o))){
                    if(i == 0){
                        httpUrl += "?";
                    }else{
                        httpUrl += "&";
                    }
                    httpUrl += o + "=" + parameter.get(o).trim().toString();
                    i++;
                }

            }
            URL url = new URL(httpUrl);
            try {
//						SSLContext sslContext = null;
//				        try {
//				            sslContext = SSLContext.getInstance("TLS"); //或SSL
//				            X509TrustManager tm = new X509TrustManager() {
//				                public X509Certificate[] getAcceptedIssuers() {
//				                    return null;
//				                }
//				                public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
//				                public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {}
//				            };
//				            X509TrustManager[] xtmArray = new X509TrustManager[] {tm};
//				            sslContext.init(null, xtmArray, new java.security.SecureRandom());
//				        } catch (GeneralSecurityException e) {
//				            e.printStackTrace();
//				        }
//				        if (sslContext != null) {
//				            HttpsURLConnection

                HttpsURLConnection urlCon = (HttpsURLConnection) url.openConnection();
                urlCon.setHostnameVerifier(new WriteReadXML.TrustAnyHostnameVerifier());
                InputStream in = urlCon.getInputStream();
                value = ReadXML(in);

            } catch (IOException e) {
                e.printStackTrace();
                value = null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            value = null;
        }
        return value;
    }






















    /**
     * 通過輸入流讀取xml
     * @param in
     * @return
     * @throws Exception
     */
    public Map readXML(InputStream in) throws Exception {
        Map m = null;
        SAXReader saxreader = new SAXReader();
        saxreader.setValidation(false);
        try {
            Document doc = saxreader.read(in);
				/*
				 *打印xml格式數據
				 */
            System.out.println(doc.asXML());
            if (doc != null) {
                m =  new HashMap();
					/*
					 * m: 自定義
					 * name: 根據xml 的節點獲取 元素值
					 */
                m.put("a", getText(doc, "name"));
                m.put("b", getText(doc, "pwd"));
                m.put("c", getText(doc, "sex"));
                return m;
            }
        } catch (DocumentException e) {
            System.out.println(WriteReadXML.class + "----" + e.getMessage());
        }
        return null;
    }
    /**--------------------------------------------發送xml-以及讀取xml-----end-------------------------------------------------**/



    /*************************************以下是創建xml節點以及讀取xml節點的一些方法************* start****************************/
    private static String getText(Document document, String xpath) {
        Node node = document.selectSingleNode(xpath);
        if (null != node && !node.getText().trim().equals(""))
            return node.getText();
        return "";
    }

    private static Element createElement(Element e, String name, String text) {
        if (text != null && !text.trim().equals("")) {
            Element el = e.addElement(name);
            el.addCDATA(text);
            return el;
        }
        return null;
    }

    public Element createElement(Element element,Map map){
        for(Object o : map.keySet()){
            String key = (String)o;
            if(map.get(o) instanceof String){
                String value = (String)map.get(o);
                createElement(element, key, value);
            }
            else if(map.get(o) instanceof Map){
                Map map1 = (Map)map.get(o);
                Element element1 = element.addElement(key);
                createElement(element1, map1);
            }
            else if(map.get(o) instanceof List){
                List lists = (List)map.get(o);
                Element element1 = element.addElement(key);
                createElement(element1,lists);
            }
        }
        return element;
    }

    public Element createElement(Element element,List lists){
        for(int i=0;i<lists.size();i++){
            Map map = (Map)lists.get(i);
            Element element1 = element.addElement("list_" + i);
            createElement(element1,map);
        }
        return element;
    }

    public boolean writeReturnmsg(Element element, Map map) throws Exception {
        createElement(element, map);
        return true;
    }




    /**
     * @category 多层Xml读取(返回Map嵌套Map)
     * @param in
     * @return
     * @throws Exception
     */
    public static Map newReadXML(InputStream in) throws Exception {
        SAXReader saxreader = new SAXReader();
        saxreader.setValidation(false);
        saxreader.setEncoding("UTF-8");

        Map value = null;
        try {
            Document doc = saxreader.read(in);
            if (doc != null) {
                Element root = doc.getRootElement();
                value = xmlToList(root,null);
                return value;
            }
        } catch (DocumentException e) {
            System.out.println(WriteReadXML.class + "----" + e.getMessage());
        }
        return null;
    }

    public static Map xmlToList(Element root,List lists)throws Exception{
        List<Element> list = root.elements();
        Map map = new HashMap();
        for(int i = 0; i < list.size(); i++){
            Element childRoot = list.get(i);

            if(childRoot.elements() != null && childRoot.elements().size() > 0){
                map.put(childRoot.getName(), xmlToList(childRoot,childRoot.elements()));
            }else{
                map.put(childRoot.getName(), childRoot.getText());
            }
        }
        return map;
    }

    /**
     * @category 讀取返回值
     * @param in
     * @return
     * @throws Exception
     */
    public static Map ReadXML(InputStream in) throws Exception {
        SAXReader saxreader = new SAXReader();
        saxreader.setValidation(false);
        saxreader.setEncoding("UTF-8");

        Map value = null;
        try {
            Document doc = saxreader.read(in);
            if (doc != null) {
                value = new HashMap();
                Element root = doc.getRootElement();
                List<Element> list = root.elements();
                for(int i = 0; i < list.size(); i++){
                    Element childRoot = list.get(i);
                    value.put(childRoot.getName(), childRoot.getText());
                }
                return value;
            }
        } catch (DocumentException e) {
            e.printStackTrace();
            System.out.println(WriteReadXML.class + "----" + e.getMessage());
        }
        return null;
    }






/**********************************end******************************************************/




    /**
     * SSL通行證
     * 验证远端的安全套
     * 不懂的去查看 javax.net.ssl.X509TrustManager 的用法（ps:qis其實我也沒搞懂,有推薦的文章可以直接發鏈接）
     *
     */
    private static class TrustAnyTrustManager implements X509TrustManager {
        /**
         * 给出同位体提供的部分或完整的证书链，构建到可信任的根的证书路径，
         * 并且返回是否可以确认和信任将其用于基于验证类型的客户端 SSL 验证。
         *  验证类型由实际使用的证书确定。
         *  例如，如果使用 RSAPublicKey，则 authType 应为 "RSA"。检查是否大小写敏感的
         * @param chain - 同位体的证书链
         * @param authType - 基于客户端证书的验证类型
         */
        public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {

        }
        /**
         * 给出同位体提供的部分或完整的证书链，构建到可信任的根的证书路径，
         * 并且返回是否可以确认和信任将其用于基于验证类型的服务器 SSL 验证。
         * 验证类型是表示为一个 String 的密码套件的密钥交换算法部分，
         * 例如 "RSA"、"DHE_DSS"。注：对于一些可输出的密码套件，密钥交换算法是在运行时的联络期间确定的。
         * 例如，对于 TLS_RSA_EXPORT_WITH_RC4_40_MD5，当临时的 RSA 密钥 用于密钥交换时 authType 应为 RSA_EXPORT，
         * 当使用来自服务器证书的密钥时 authType 应为 RSA。检查是否大小写敏感的。
         * chain - 同位体的证书链
         * authType - 使用的密钥交换算法
         */
        public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {

        }
        /**
         * 可接受的 CA 发行者证书的非 null（可能为空）的数组。
         */
        public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[]{};
        }
    }
    private static class TrustAnyHostnameVerifier implements HostnameVerifier {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    }

    public static boolean isEmpty(String s) {
        return s == null || s.trim().length() == 0 ? true : false;
    }


    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("logid", "3155618");
        map.put("page", "0");
        map.put("num", "5");
        String url = "http://192.168.41.125:8080/epsf.do?method=getShopcars";
        Map aaa = Send_XML(url, "status", map);

        for(Object o : aaa.keySet()){
            String key = (String)o;
            Map value = (Map)aaa.get(key);
            System.out.println(key+"=");
            for(Object o1 : value.keySet()){
                String key1 = (String)o1;
                String value1 = (String)value.get(key1);
                System.out.println(key1+"="+value1);
            }
        }
    }











}
